<?php

/**
 * Auth_PEAR wiki module :O
 */

// Don't let anonymous people do things...
$wgGroupPermissions['*']['createaccount']   = false;
$wgGroupPermissions['*']['read']            = true;
$wgGroupPermissions['*']['edit']            = false;

// Most extra permission abilities go to this group
$wgGroupPermissions['peargroup']['block']           = true;
$wgGroupPermissions['peargroup']['createaccount']   = true;
$wgGroupPermissions['peargroup']['delete']          = true;
$wgGroupPermissions['peargroup']['deletedhistory']  = true; // can view deleted history entries, but not see or restore the text
$wgGroupPermissions['peargroup']['editinterface']   = true;
$wgGroupPermissions['peargroup']['import']          = true;
$wgGroupPermissions['peargroup']['importupload']    = true;
$wgGroupPermissions['peargroup']['move']            = true;
$wgGroupPermissions['peargroup']['patrol']          = true;
$wgGroupPermissions['peargroup']['autopatrol']       = true; // not in version 1.6.9, 1.8.2, 1.8.3
$wgGroupPermissions['peargroup']['protect']         = true;
$wgGroupPermissions['peargroup']['proxyunbannable'] = true; //not in version 1.6.9
$wgGroupPermissions['peargroup']['rollback']        = true;
$wgGroupPermissions['peargroup']['trackback']       = true; //not in version 1.6.9
$wgGroupPermissions['peargroup']['upload']          = true;
$wgGroupPermissions['peargroup']['reupload']        = true;
$wgGroupPermissions['peargroup']['reupload-shared'] = true;
$wgGroupPermissions['peargroup']['unwatchedpages']  = true;
$wgGroupPermissions['peargroup']['autoconfirmed']   = true;
$wgGroupPermissions['peargroup']['upload_by_url']   = true; //not in version 1.6.9
$wgGroupPermissions['peargroup']['ipblock-exempt']   = true; // not in version 1.6.9, 1.8.2, 1.8.3
// The Auth_imap class is an AuthPlugin so make sure we have this included.
require_once 'AuthPlugin.php';

class Auth_PEAR_Rest extends AuthPlugin {

    public $pearUser;

    private $groupMembers = array(
        'jeichorn', 
        'cellog', 
        'dufuz',
        'davidc', 
        'pmjones', 
        'cweiske', 
        'arnaud',
        'mj',
    );
    
    public function __construct() 
    {
        
    }

    /**
     * Disallow password change.
     *
     * @return bool
     */
    function allowPasswordChange() 
    {
        return false;
    }

    /**
     * This should not be called because we do not allow password change.  Always
     * fail by returning false.
     *
     * @param $user User object.
     * @param $password String: password.
     * @return bool
     * @public
     */
    function setPassword($user, $password) 
    {
        return false;
    }

    /**
     * We don't support this but we have to return true for preferences to save.
     *
     * @param $user User object.
     * @return bool
     * @public
     */
    function updateExternalDB($user) 
    {
        return true;
    }

    /**
     * We can't create external accounts so return false.
     *
     * @return bool
     * @public
     */
    function canCreateAccounts() 
    {
        return false;
    }

    /**
     * We don't support adding users to whatever service provides REMOTE_USER, so
     * fail by always returning false.
     *
     * @param User $user
     * @param string $password
     * @return bool
     * @public
     */
    function addUser($user, $password) 
    {
        return false;
    }


    /**
     * Pretend all users exist.  This is checked by authenticateUserData to
     * determine if a user exists in our 'db'.  By returning true we tell it that
     * it can create a local wiki user automatically.
     *
     * @param $username String: username.
     * @return bool
     * @public
     */
    function userExists($username) 
    {
        return true;
    }

    /**
     * Attempt to authenticate the user via IMAP.
     *
     * @param $username String: username.
     * @param $password String: user password.
     * @return bool
     * @public
     */
    function authenticate($username, $password) 
    {
        $salt    = file_get_contents('http://pear.php.net/rest-login.php/getsalt');
        $cookies = array_values(preg_grep('/Set-Cookie:/', $http_response_header));
        
        preg_match('/PHPSESSID=(.+); /', $cookies[0], $session);
        $pass = md5($salt . md5($password));
        
        $opts = array(
            'http' => array(
                'method' => 'POST',
                'header' => 'Cookie: PHPSESSID=' . $session[1] . ';',
                'content' => http_build_query(
                    array(
                        'username' => $username, 
                        'password' => $pass, 
                        'karma' => 'pear.dev'
                    )
                )
            )
        );
        
        $context = stream_context_create($opts);
        
        $res = file_get_contents(
            'http://pear.php.net/rest-login.php/validate',                         
            false,
            $context
        );
        
        $this->pearUser['username'] = $username;

        if (in_array(strtolower($username), $this->groupMembers)) {
            $this->makeSuperCoolAdmin();
        }
        
        if ($res[0]) {
            switch ($res[0]) {
                case '7' :
                    $error = substr($res, 2);
                    return false; // Invalid login
                    break;
                case '8' :
                    return true; // Login == success :D
                    break;
                default :
                return false; // DB Error
            }
        }
    }

    /**
     * Check to see if the specific domain is a valid domain.
     *
     * @param $domain String: authentication domain.
     * @return bool
     * @public
     */
    function validDomain($domain) 
    {
        return true;
    }

    /**
     * When a user logs in, optionally fill in preferences and such.
     * For instance, you might pull the email address or real name from the
     * external user database.
     *
     * The User object is passed by reference so it can be modified; don't
     * forget the & on your function declaration.
     *
     * @param User $user
     * @public
     */
    function updateUser(&$user) 
    {
        // We only set this stuff when accounts are created.
        return true;
    }

    /**
     * Return true because the wiki should create a new local account
     * automatically when asked to login a user who doesn't exist locally but
     * does in the external auth database.
     *
     * @return bool
     * @public
     */
    function autoCreate() 
    {
        return true;
    }

    /**
     * Return true to prevent logins that don't authenticate here from being
     * checked against the local database's password fields.
     *
     * @return bool
     * @public
     */
    function strict() 
    {
        return true;
    }

    /**
     * When creating a user account, optionally fill in preferences and such.
     * For instance, you might pull the email address or real name from the
     * external user database.
     *
     * @param $user User object.
     * @public
     */
    function initUser(&$user) 
    {
        global $_SERVER;
        $username = $this->pearUser['username'];

        // Using your own methods put the users real name here.
        $user->setRealName('');
        // Using your own methods put the users email here.
        $user->setEmail($username . '@php.net');

        $user->setToken();        
        $user->saveSettings();
    }

    /**
     * Modify options in the login template.  This shouldn't be very important
     * because no one should really be bothering with the login page.
     *
     * @param $template UserLoginTemplate object.
     * @public
     */
    function modifyUITemplate(&$template) 
    {

    }

    /**
     * Normalize user names to the mediawiki standard to prevent duplicate
     * accounts.
     *
     * @param $username String: username.
     * @return string
     * @public
     */
    function getCanonicalName($username) 
    {
        // lowercase the username
        $username = strtolower($username);
        // uppercase first letter to make mediawiki happy
        $username[0] = strtoupper($username[0]);
        return $username;
    }

    /**
     * Make Super Cool Admin
     *
     * This function will call the methods
     * to make sure the user is made an
     * administrator on the system.
     */
    public function makeSuperCoolAdmin()
    {
        global $wgUserGroups, $wgUser;
        $wgUser->mGroups = 'peargroup';
        
        $wgUser->mRights[] = 'block';
        $wgUser->mRights[] = 'createAccount';
        $wgUser->mRights[] = 'delete';
        $wgUser->mRights[] = 'deletedhistory';
        $wgUser->mRights[] = 'editinterface';
        $wgUser->mRights[] = 'import';
        $wgUser->mRights[] = 'importupload';
        $wgUser->mRights[] = 'move';
        $wgUser->mRights[] = 'patrol';
        $wgUser->mRights[] = 'protect';
        $wgUser->mRights[] = 'proxyunbannable';
        $wgUser->mRights[] = 'rollback';
        $wgUser->mRights[] = 'trackback';
        $wgUser->mRights[] = 'upload';
        $wgUser->mRights[] = 'reupload';
        $wgUser->mRights[] = 'reupload-shared';
        $wgUser->mRights[] = 'unwatchedpages';
        $wgUser->mRights[] = 'autoconfirmed';
        $wgUser->mRights[] = 'upload_by_url';
        $wgUser->mRights[] = 'ipblock-exempt';

        $wgUser->mEffectiveGroups[] = 'peargroup';

        return;
    }
}
?>
